/* eslint-disable space-after-function-paren */
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
import { FBXLoader } from 'three/addons/loaders/FBXLoader.js';

import Stats from 'three/examples/jsm/libs/stats.module.js';



/* eslint-disable no-console */
class BaseThreeScene{
  constructor(sceneDom,onFinish,onprogress,onclick,settings) {
    this.container = sceneDom;
    this.camera;
    this.camera_look_pos = new THREE.Vector3(0,0,0);
    this.scene;
    this.renderer;
    this.labelRenderer;
    this.clock = new THREE.Clock();
    this._pre_mouse = 0;
    this._click_duration = 0.1;
    // 配置
    this.settings = settings
    this.onFinish = onFinish;
    this.onprogress = onprogress;
    this.onclick = onclick;

    this.composer;
    this.outlinePass;
    this.stats;
    // 科技背景
    this.bgGroup = new THREE.Group();
    this.groundMT = null;


    // 动画部分
    this.PlayerMixer;
    this.PlayerAnimations = [];
    this.preAnimation = null; //记录上次动作，方便做动画过渡切换
    this.actionMixTime = 0.5; //动作切换混合时间

    this.init();
  }

  init() {

    // // 初始化材质
    this.initMaterial();
       
    // //   初始化场景
    this.initScene();

    // // 初始化相机
    this.initCamera();

    //   // 初始化灯光
    this.initLight();
    
    // // 初始化渲染器
    this.initRenderer();
    this.iniLabelRenderer();

    this.initControls();

    this.addModel();
        

    this.container.addEventListener('resize', this.onResize.bind(this)); 
    this.container.addEventListener('mousedown', this.onmousedown.bind(this)); 
    this.container.addEventListener('mouseup', this.click.bind(this)); 
  

    if(this.settings.debug) {
      let axesHelper = new THREE.AxesHelper(250);
      this.scene.add(axesHelper);

      this.stats = new Stats();
      this.container.appendChild(this.stats.dom); 
    }
  }


  initMaterial(){
    let TextureLoader = new THREE.TextureLoader();

  }

  onmousedown() {
    this._pre_mouse = this.clock.getElapsedTime();
  }
  click(event) {
    let now = this.clock.getElapsedTime();
    if(now - this._pre_mouse > this._click_duration)return;
    let Sx = event.clientX; //鼠标单击位置横坐标
    let Sy = event.clientY; //鼠标单击位置纵坐标
    //屏幕坐标转WebGL标准设备坐标
    let width  = this.container.clientWidth; //窗口文档显示区的宽度
    let height = this.container.clientHeight; //窗口文档显示区的高度

    let left = this.container.clientLeft;
    let top  = this.container.clientTop;
    let x = ((Sx - left)  / width) * 2 - 1; //WebGL标准设备横坐标
    let y = -((Sy - top) / height) * 2 + 1; //WebGL标准设备纵坐标
    let raycaster = new THREE.Raycaster();
    raycaster.setFromCamera(new THREE.Vector2(x, y), this.camera);
    let intersects = raycaster.intersectObjects(this.settings.ray_meshs,true);
    if(intersects.length > 0) {
      this.onclick(intersects[0].object);
    }
  }

  mouseStore(event) {
    let Sx = event.clientX; //鼠标单击位置横坐标
    let Sy = event.clientY; //鼠标单击位置纵坐标
    //屏幕坐标转WebGL标准设备坐标
    let width  = this.container.clientWidth; //窗口文档显示区的宽度
    let height = this.container.clientHeight; //窗口文档显示区的高度

    let left = this.container.clientLeft;
    let top  = this.container.clientTop;
    let x = ((Sx - left)  / width) * 2 - 1; //WebGL标准设备横坐标
    let y = -((Sy - top) / height) * 2 + 1; //WebGL标准设备纵坐标
    let raycaster = new THREE.Raycaster();
    raycaster.setFromCamera(new THREE.Vector2(x, y), this.camera);
    let intersects = raycaster.intersectObjects(this.settings.ray_meshs,true);
    if(intersects.length > 0) {
      const selectedObjects = [intersects[0].object];
      this.outlinePass.selectedObjects = selectedObjects;
    }else{
      this.outlinePass.selectedObjects = [];
    }
  }


  addModel() {
    let _self = this;
    const dracoLoader = new DRACOLoader();
    const loader = new GLTFLoader();
    loader.setDRACOLoader(dracoLoader);

    if( _self.settings.isLoadModel === false ) return;
    loader.load( _self.settings.modelUrl, function( gltf ) {
        // name: 'Armature'
      _self.PlayerMixer = new THREE.AnimationMixer( gltf.scene.children[0] );

      gltf.scene.scale.set(_self.settings.modelScale,_self.settings.modelScale,_self.settings.modelScale);
      _self.scene.add( gltf.scene );
      _self.animate();
      _self.onFinish(gltf.scene)
      // 如果配置了动画资源就执行加载动画资源
      if( _self.settings.animations.length > 0)
      {
        _self.loadAnimations();
      }

    },_self.onprogress);
  }

  loadAnimations()
  {
    const _self = this;
    const loader = new FBXLoader();
    _self.settings.animations.forEach(((item)=>{
        let type = item.type;
        let name = item.name;
        let autoPlay = item.autoPlay;
        // 如果没有该类型，就创建该类型
        if(!_self.PlayerAnimations[type])
        {
        _self.PlayerAnimations[type] = [];
        }
        let url = item.url;
        loader.load( url, function ( object ) {
            const action = _self.PlayerMixer.clipAction( object.animations[ 0 ] );
            let animation = {
                action:action,
                url:url,
                name:name
            }
            _self.PlayerAnimations[type].push(animation)
            console.log("动画："+name+"加载完毕")
            if(autoPlay)
            {
                action.play();
                _self.preAnimation = animation;
            }
        });
    }))
  }


    //动作切换 
  changePlayerAnimation(type)
  {
    let _self = this;
    if(_self.PlayerAnimations[type])
    {
        if(_self.preAnimation && _self.preAnimation.type == type) return false;
        let aniIndex = Math.floor( Math.random() * _self.PlayerAnimations[type].length );
        let animation = _self.PlayerAnimations[type][aniIndex];
        animation.action.reset().fadeIn(_self.actionMixTime).play();
        if(_self.preAnimation)
        {
            _self.preAnimation.action.fadeOut(_self.actionMixTime);
        }
        _self.preAnimation = animation;

    }
  }

  createGround(groundSize) {
    let _self = this;
    let group = new THREE.Group();
    const loader = new THREE.TextureLoader();
    let ground = loader.load('/textures/ground_dian.png');
    let mask = loader.load('/textures/light_r.png');
    mask.wrapS = THREE.ClampToEdgeWrapping;
    mask.wrapT = THREE.ClampToEdgeWrapping;
    
    let repeatNum = _self.settings.reapeat;
    ground.wrapS = THREE.RepeatWrapping;
    ground.wrapT = THREE.RepeatWrapping;
    ground.repeat.x = repeatNum;
    ground.repeat.y = repeatNum;
        
    let vertexShader =
          '  varying vec2 vUv;    void main(){        vUv = uv;        gl_Position = projectionMatrix*viewMatrix*modelMatrix*vec4( position, 1.0 );    }';
    let fragmentShader =
          'uniform sampler2D groundMap;uniform float repeatNum;uniform sampler2D maskMap;uniform float time;uniform vec3 baseColor;uniform vec3 bgColor;uniform float alpha;uniform float opacity;uniform float speed;uniform vec3  flowColor; uniform float glowFactor;varying vec2 vUv;void main() {    float t=mod(time/5.*speed,1.);     vec2 uv=abs((vUv-vec2(0.5))*2.0);     float dis = length(uv);    float r = t-dis;     vec4 col=texture2D( groundMap, vUv * repeatNum);     vec3 finalCol;     vec4 mask = texture2D(maskMap, vec2(0.5,r));    finalCol = mix(bgColor,flowColor,clamp(0.,1.,mask.a*glowFactor));     gl_FragColor= vec4(finalCol.rgb,(alpha+mask.a*glowFactor)*col.a*(1.-dis)*opacity);}';
    this.groundMT = new THREE.ShaderMaterial({
      uniforms: {
        bgColor: { value: new THREE.Color(_self.settings.bgColor) },
        baseColor: { value: new THREE.Color(_self.settings.baseColor) },
        time: { value: 35 },
        repeatNum: { value: repeatNum },
        groundMap: { value: ground },
        maskMap: { value: mask },
    
        alpha: { value: 0.0 },
        opacity: { value: 1 },
        speed: { value: 0.2 },
        flowColor: { value: new THREE.Color(_self.settings.flowColor) },
        glowFactor: { value: _self.settings.glowFactor }
      },
      transparent: true,
      vertexShader: vertexShader,
      fragmentShader: fragmentShader
    });
    
      
    let gezi = loader.load('/textures/dd2.png');
    gezi.repeat.x = _self.settings.reapeat * 60;
    gezi.repeat.y =_self.settings.reapeat * 60;
    gezi.wrapS = THREE.RepeatWrapping;
    gezi.wrapT = THREE.RepeatWrapping;
    
    
    const CircleGeometry = new THREE.CircleGeometry(groundSize * 5, 64);
    let MeshLambertMaterial = new THREE.MeshStandardMaterial({
      color: new THREE.Color('rgb(255,255,255)'),
      map: gezi,
      transparent: true,
      opacity:0.2
    });
    const bg2 = new THREE.Mesh(CircleGeometry, MeshLambertMaterial);
    // bg2.position.z = 0;
    bg2.renderOrder = 10;
    group.add( bg2 );
    

    
    const geometry = new THREE.CircleGeometry(groundSize * 1.2, 64);
    const plane = new THREE.Mesh(geometry, this.groundMT);
    group.add(plane);
    
    let maks2 = loader.load('/textures/bg_dian.png');
    const CircleGeometry2 = new THREE.CircleGeometry(groundSize * 0.75, 64);
    let MeshLambertMaterial2 = new THREE.MeshStandardMaterial({
      color: 'rgb(255,255,255)',
      map: maks2,
      transparent: true,
      opacity:0.6
    });
    const bg3 = new THREE.Mesh(CircleGeometry2, MeshLambertMaterial2);
    bg3.position.z = -0.2;
    bg3.position.y = 3;
    bg3.renderOrder = 1;
    group.add( bg3);
    
    group.rotateX(-Math.PI / 2);
    // group.position.copy(_self.lookAtPos);
    _self.bgGroup.add(group);
    _self.scene.add(_self.bgGroup);

  }

  initScene() {
    this.scene = new THREE.Scene();
  }
  initCamera() {
    let width  = this.container.clientWidth; //窗口文档显示区的宽度
    let height = this.container.clientHeight; //窗口文档显示区的高度
    let k      = width / height; //Three.js输出的Cnavas画布宽高比
    this.camera = new THREE.PerspectiveCamera( this.settings.camera_fov, k , this.settings.camera_near,  this.settings.camera_far );
    let pos =  this.settings.isPlay ? this.settings.camera_fly_initpos : this.settings.camera_initpos;
    this.camera.position.set(pos.x, pos.y, pos.z);
  }
  initLight() {
    let _self = this;
    //环境光
    // var ambient = new THREE.AmbientLight(0xffffff, 0.6);
    // this.scene.add(ambient);
    new RGBELoader().load( _self.settings.hdrURl, function( texture ) {
      texture.mapping = THREE.EquirectangularReflectionMapping;
      _self.scene.environment = texture;
      _self.scene.environmentRotation = new THREE.Euler(_self.settings.hdr_rotation.x,_self.settings.hdr_rotation.y,_self.settings.hdr_rotation.z)
    })
        

  }
  initRenderer() {
    let width  = this.container.clientWidth; //窗口文档显示区的宽度
    let height = this.container.clientHeight; //窗口文档显示区的高度
    // , alpha: true
    this.renderer = new THREE.WebGLRenderer({ antialias: true , precision:'highp',alpha:true });
    // 设置屏幕像素比
    this.renderer.setPixelRatio(window.devicePixelRatio);
    // 渲染的尺寸大小
    this.renderer.setSize(width, height);
    this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
    this.renderer.toneMappingExposure = this.settings.exposure;
    this.container.appendChild(this.renderer.domElement);

    // 外放光后期处理
    // this.composer = new EffectComposer( this.renderer );
    // const renderPass = new RenderPass( this.scene, this.camera );
    // this.composer.addPass( renderPass );

    // this.outlinePass = new OutlinePass( new THREE.Vector2( width, height ), this.scene, this.camera );
    // this.composer.addPass( this.outlinePass );

  }

  iniLabelRenderer(){
    let width  = this.container.clientWidth; //窗口文档显示区的宽度
    let height = this.container.clientHeight; //窗口文档显示区的高度
    this.labelRenderer = new CSS2DRenderer();
    this.labelRenderer.setSize(width, height);
    this.labelRenderer.domElement.style.position = 'absolute';
    // 相对鼠标单击位置偏移
    this.labelRenderer.domElement.style.top = '0px';
    this.labelRenderer.domElement.style.left = '0px';
    // //设置.pointerEvents=none，以免模型标签HTML元素遮挡鼠标选择场景模型
    this.labelRenderer.domElement.style.pointerEvents = 'none';
    this.container.appendChild(this.labelRenderer.domElement);
  }
  render() {
    const delta = this.clock.getDelta();

    this.controls.update(delta);
    if(this.settings.debug) {
      this.stats.update();
      // console.log(this.camera.position);
    }

    if ( this.PlayerMixer ) this.PlayerMixer.update( delta );

    if (this.settings.bgisShow && this.groundMT) {
      this.groundMT.uniforms.time.value += 0.05;
      if (this.groundMT.uniforms.time.value > 20) {
        this.groundMT.uniforms.time.value = 0;
      }
    }

    this.renderer.render(this.scene, this.camera);
    this.labelRenderer.render(this.scene,this.camera);
    // this.composer.render();
  }
  animate() {
    this.renderer.setAnimationLoop(this.render.bind(this));
  }
  initControls() {
    this.controls = new OrbitControls(this.camera, this.renderer.domElement);
    let target = this.settings.control_target;
    this.controls.target.set( target.x,target.y,target.z);
    // 使动画循环使用时阻尼或自转 意思是否有惯性
    this.controls.enableDamping = false;
    // //动态阻尼系数 就是鼠标拖拽旋转灵敏度
    this.controls.dampingFactor = 0.05;
    this.controls.enableZoom = true;
    this.controls.minDistance = this.settings.control_minDistance;
    this.controls.maxDistance = this.settings.control_maxDistance;
    this.controls.autoRotate = this.settings.control_autoRotate;
    this.controls.autoRotateSpeed = this.settings.control_autoSpeed;
    this.controls.enablePan  = this.settings.control_pan;
    this.controls.maxPolarAngle  = Math.PI / 2;

  }
  onResize() {
    let width  = window.innerWidth; //窗口文档显示区的宽度
    let height = window.innerHeight; //窗口文档显示区的高度
    this.camera.aspect = width / height;
    this.camera.updateProjectionMatrix();
    this.renderer.setSize(width, height);
    this.labelRenderer.setSize(width, height);
    // this.composer.setSize( width, height );
    this.render();

  }
  dispose() {
    this.scene.traverse(child => {
      if(child.isMesh) {
        child.geometry.dispose();
        child.material.dispose();
      }else if(child instanceof THREE.Group || child instanceof THREE.Object3D) {
        child.clear();
      }
      this.scene.remove(child);
      child = null;
    })

    // console.log("释放资源")
  }
}



export default BaseThreeScene